/**
 * IndexedDB 数据存储服务
 * 用于管理医院场景数据的本地存储
 */

// 数据库配置
const DB_NAME = 'HospitalDigitalTwin'
const DB_VERSION = 2  // 升级版本以触发数据库结构更新

// 数据表定义
export interface StoreTables {
  hospitals: HospitalData
  floors: FloorData
  pois: POIData
  scenarios: ScenarioData
  simulations: SimulationData
  assets: AssetData
  // 新增：医院建筑管理相关数据表
  hospital_buildings: HospitalBuildingData
  departments: DepartmentData
  medical_equipment: MedicalEquipmentData
}

// 数据类型定义
export interface HospitalData {
  id: string
  name: string
  address: string
  center: [number, number] // 经纬度中心点
  bounds: {
    north: number
    south: number
    east: number
    west: number
  }
  floors: string[] // 楼层ID列表
  metadata: Record<string, any>
  createdAt: Date
  updatedAt: Date
}

export interface FloorData {
  id: string
  hospitalId: string
  name: string
  level: number // 楼层级别（如：-1, 0, 1, 2）
  svgUrl?: string // SVG模型文件URL
  glbUrl?: string // GLB模型文件URL
  bounds: {
    north: number
    south: number
    east: number
    west: number
  }
  pois: string[] // POI ID列表
  metadata: Record<string, any>
  createdAt: Date
  updatedAt: Date
}

export interface POIData {
  id: string
  hospitalId: string
  floorId: string
  name: string
  type: 'department' | 'equipment' | 'entrance' | 'elevator' | 'stairs' | 'toilet' | 'emergency' | 'cafe' | 'pharmacy' | 'lab' | 'imaging'
  position: [number, number] // 经纬度
  description?: string
  capacity?: number
  status: 'active' | 'inactive' | 'maintenance'
  metadata: Record<string, any>
  createdAt: Date
  updatedAt: Date
}

export interface ScenarioData {
  id: string
  hospitalId: string
  name: string
  description: string
  type: 'normal' | 'emergency' | 'peak' | 'night'
  parameters: {
    arrivalRate: number
    serviceTimes: Record<string, { mean: number; std: number }>
    capacity: Record<string, number>
    policies: string[]
  }
  metadata: Record<string, any>
  createdAt: Date
  updatedAt: Date
}

export interface SimulationData {
  id: string
  hospitalId: string
  scenarioId: string
  name: string
  status: 'pending' | 'running' | 'completed' | 'failed'
  progress: number
  startTime?: Date
  endTime?: Date
  results?: {
    kpis: Record<string, number>
    heatmapFrames: string[]
    trajectories: any[]
    bottlenecks: any[]
  }
  metadata: Record<string, any>
  createdAt: Date
  updatedAt: Date
}

export interface AssetData {
  id: string
  name: string
  type: 'bed' | 'equipment' | 'furniture' | 'sign' | 'decoration'
  category: string
  modelUrl?: string
  thumbnailUrl?: string
  dimensions: {
    width: number
    height: number
    depth: number
  }
  metadata: Record<string, any>
  createdAt: Date
  updatedAt: Date
}

// 新增：医院数据类型定义
export interface HospitalBuildingData {
  id: string
  hospitalId: string
  name: string
  description: string
  center: [number, number] // 建筑中心经纬度
  bounds: {
    north: number
    south: number
    east: number
    west: number
  }
  modelPath: string // 3D模型路径（GLB/GLTF）
  floors: string[] // 楼层ID列表
  metadata: Record<string, any>
  createdAt: Date
  updatedAt: Date
}

// 科室/部门数据
export interface DepartmentData {
  id: string
  hospitalId: string
  buildingId?: string
  floorId?: string
  name: string
  type: 'outpatient' | 'inpatient' | 'emergency' | 'surgery' | 'laboratory' | 'radiology' | 'pharmacy' | 'administration'
  position: [number, number] // 经纬度
  modelInfo?: {
    meshName: string // 3D模型中的mesh名称
    boundingBox?: {
      min: [number, number, number]
      max: [number, number, number]
    }
  }
  description?: string
  contact?: {
    phone?: string
    hours?: string
    director?: string
  }
  capacity?: number // 床位数或容量
  status: 'active' | 'inactive' | 'maintenance'
  metadata: Record<string, any>
  createdAt: Date
  updatedAt: Date
}

// 医疗设备/设施数据
export interface MedicalEquipmentData {
  id: string
  hospitalId: string
  departmentId?: string
  floorId?: string
  name: string
  type: 'ct' | 'mri' | 'xray' | 'ultrasound' | 'bed' | 'wheelchair' | 'defibrillator' | 'ventilator' | 'toilet' | 'elevator' | 'entrance' | 'exit'
  position: [number, number] // 经纬度
  description?: string
  specifications?: string // 设备规格
  manufacturer?: string // 制造商
  status: 'active' | 'inactive' | 'maintenance' | 'reserved'
  metadata: Record<string, any>
  createdAt: Date
  updatedAt: Date
}

class IndexedDBService {
  private db: IDBDatabase | null = null
  public initPromise: Promise<void>

  constructor() {
    this.initPromise = this.initDB()
  }

  /**
   * 初始化数据库
   */
  private async initDB(): Promise<void> {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open(DB_NAME, DB_VERSION)

      request.onerror = () => {
        reject(new Error('Failed to open IndexedDB'))
      }

      request.onsuccess = () => {
        this.db = request.result
        resolve()
      }

      request.onupgradeneeded = (event) => {
        const db = (event.target as IDBOpenDBRequest).result

        // 创建医院表
        if (!db.objectStoreNames.contains('hospitals')) {
          const hospitalStore = db.createObjectStore('hospitals', { keyPath: 'id' })
          hospitalStore.createIndex('name', 'name', { unique: false })
          hospitalStore.createIndex('createdAt', 'createdAt', { unique: false })
        }

        // 创建楼层表
        if (!db.objectStoreNames.contains('floors')) {
          const floorStore = db.createObjectStore('floors', { keyPath: 'id' })
          floorStore.createIndex('hospitalId', 'hospitalId', { unique: false })
          floorStore.createIndex('level', 'level', { unique: false })
        }

        // 创建POI表
        if (!db.objectStoreNames.contains('pois')) {
          const poiStore = db.createObjectStore('pois', { keyPath: 'id' })
          poiStore.createIndex('hospitalId', 'hospitalId', { unique: false })
          poiStore.createIndex('floorId', 'floorId', { unique: false })
          poiStore.createIndex('type', 'type', { unique: false })
        }

        // 创建场景表
        if (!db.objectStoreNames.contains('scenarios')) {
          const scenarioStore = db.createObjectStore('scenarios', { keyPath: 'id' })
          scenarioStore.createIndex('hospitalId', 'hospitalId', { unique: false })
          scenarioStore.createIndex('type', 'type', { unique: false })
        }

        // 创建仿真表
        if (!db.objectStoreNames.contains('simulations')) {
          const simulationStore = db.createObjectStore('simulations', { keyPath: 'id' })
          simulationStore.createIndex('hospitalId', 'hospitalId', { unique: false })
          simulationStore.createIndex('scenarioId', 'scenarioId', { unique: false })
          simulationStore.createIndex('status', 'status', { unique: false })
          simulationStore.createIndex('createdAt', 'createdAt', { unique: false })
        }

        // 创建资产表
        if (!db.objectStoreNames.contains('assets')) {
          const assetStore = db.createObjectStore('assets', { keyPath: 'id' })
          assetStore.createIndex('type', 'type', { unique: false })
          assetStore.createIndex('category', 'category', { unique: false })
        }

        // 创建医院建筑表
        if (!db.objectStoreNames.contains('hospital_buildings')) {
          const buildingStore = db.createObjectStore('hospital_buildings', { keyPath: 'id' })
          buildingStore.createIndex('hospitalId', 'hospitalId', { unique: false })
          buildingStore.createIndex('name', 'name', { unique: false })
          buildingStore.createIndex('createdAt', 'createdAt', { unique: false })
        }

        // 创建科室表
        if (!db.objectStoreNames.contains('departments')) {
          const departmentStore = db.createObjectStore('departments', { keyPath: 'id' })
          departmentStore.createIndex('hospitalId', 'hospitalId', { unique: false })
          departmentStore.createIndex('buildingId', 'buildingId', { unique: false })
          departmentStore.createIndex('floorId', 'floorId', { unique: false })
          departmentStore.createIndex('type', 'type', { unique: false })
          departmentStore.createIndex('status', 'status', { unique: false })
        }

        // 创建医疗设备表
        if (!db.objectStoreNames.contains('medical_equipment')) {
          const equipmentStore = db.createObjectStore('medical_equipment', { keyPath: 'id' })
          equipmentStore.createIndex('hospitalId', 'hospitalId', { unique: false })
          equipmentStore.createIndex('departmentId', 'departmentId', { unique: false })
          equipmentStore.createIndex('floorId', 'floorId', { unique: false })
          equipmentStore.createIndex('type', 'type', { unique: false })
          equipmentStore.createIndex('status', 'status', { unique: false })
        }
      }
    })
  }

  /**
   * 确保数据库已初始化
   */
  private async ensureInitialized(): Promise<void> {
    if (this.initPromise) {
      await this.initPromise
    }
    if (!this.db) {
      throw new Error('Database not initialized')
    }
  }

  /**
   * 添加数据
   */
  async add<T extends keyof StoreTables>(
    storeName: T,
    data: StoreTables[T]
  ): Promise<string> {
    await this.ensureInitialized()

    return new Promise((resolve, reject) => {
      const transaction = this.db!.transaction([storeName], 'readwrite')
      const store = transaction.objectStore(storeName)
      
      const request = store.add(data)
      
      request.onsuccess = () => {
        resolve(request.result as string)
      }
      
      request.onerror = () => {
        reject(new Error(`Failed to add data to ${storeName}`))
      }
    })
  }

  /**
   * 更新数据
   */
  async update<T extends keyof StoreTables>(
    storeName: T,
    data: StoreTables[T]
  ): Promise<void> {
    await this.ensureInitialized()

    return new Promise((resolve, reject) => {
      const transaction = this.db!.transaction([storeName], 'readwrite')
      const store = transaction.objectStore(storeName)
      
      const request = store.put(data)
      
      request.onsuccess = () => {
        resolve()
      }
      
      request.onerror = () => {
        reject(new Error(`Failed to update data in ${storeName}`))
      }
    })
  }

  /**
   * 插入或更新数据（upsert）
   * 如果数据存在则更新，不存在则插入
   */
  async upsert<T extends keyof StoreTables>(
    storeName: T,
    data: StoreTables[T]
  ): Promise<string> {
    await this.ensureInitialized()

    return new Promise((resolve, reject) => {
      const transaction = this.db!.transaction([storeName], 'readwrite')
      const store = transaction.objectStore(storeName)
      
      const request = store.put(data)
      
      request.onsuccess = () => {
        resolve(request.result as string)
      }
      
      request.onerror = () => {
        reject(new Error(`Failed to upsert data to ${storeName}: ${request.error?.message || 'Unknown error'}`))
      }
    })
  }

  /**
   * 获取单条数据
   */
  async get<T extends keyof StoreTables>(
    storeName: T,
    id: string
  ): Promise<StoreTables[T] | null> {
    await this.ensureInitialized()

    return new Promise((resolve, reject) => {
      const transaction = this.db!.transaction([storeName], 'readonly')
      const store = transaction.objectStore(storeName)
      
      const request = store.get(id)
      
      request.onsuccess = () => {
        resolve(request.result || null)
      }
      
      request.onerror = () => {
        reject(new Error(`Failed to get data from ${storeName}`))
      }
    })
  }

  /**
   * 获取所有数据
   */
  async getAll<T extends keyof StoreTables>(
    storeName: T
  ): Promise<StoreTables[T][]> {
    await this.ensureInitialized()

    return new Promise((resolve, reject) => {
      const transaction = this.db!.transaction([storeName], 'readonly')
      const store = transaction.objectStore(storeName)
      
      const request = store.getAll()
      
      request.onsuccess = () => {
        resolve(request.result)
      }
      
      request.onerror = () => {
        reject(new Error(`Failed to get all data from ${storeName}`))
      }
    })
  }

  /**
   * 根据索引查询
   */
  async getByIndex<T extends keyof StoreTables>(
    storeName: T,
    indexName: string,
    value: any
  ): Promise<StoreTables[T][]> {
    await this.ensureInitialized()

    return new Promise((resolve, reject) => {
      const transaction = this.db!.transaction([storeName], 'readonly')
      const store = transaction.objectStore(storeName)
      const index = store.index(indexName)
      
      const request = index.getAll(value)
      
      request.onsuccess = () => {
        resolve(request.result)
      }
      
      request.onerror = () => {
        reject(new Error(`Failed to query ${storeName} by ${indexName}`))
      }
    })
  }

  /**
   * 删除数据
   */
  async delete<T extends keyof StoreTables>(
    storeName: T,
    id: string
  ): Promise<void> {
    await this.ensureInitialized()

    return new Promise((resolve, reject) => {
      const transaction = this.db!.transaction([storeName], 'readwrite')
      const store = transaction.objectStore(storeName)
      
      const request = store.delete(id)
      
      request.onsuccess = () => {
        resolve()
      }
      
      request.onerror = () => {
        reject(new Error(`Failed to delete data from ${storeName}`))
      }
    })
  }

  /**
   * 清空表
   */
  async clear<T extends keyof StoreTables>(storeName: T): Promise<void> {
    await this.ensureInitialized()

    return new Promise((resolve, reject) => {
      const transaction = this.db!.transaction([storeName], 'readwrite')
      const store = transaction.objectStore(storeName)
      
      const request = store.clear()
      
      request.onsuccess = () => {
        resolve()
      }
      
      request.onerror = () => {
        reject(new Error(`Failed to clear ${storeName}`))
      }
    })
  }

  /**
   * 分页查询
   */
  async paginate<T extends keyof StoreTables>(
    storeName: T,
    page: number = 1,
    pageSize: number = 20,
    indexName?: string,
    direction: 'next' | 'prev' = 'next'
  ): Promise<{
    data: StoreTables[T][]
    hasMore: boolean
    total: number
  }> {
    await this.ensureInitialized()

    return new Promise((resolve, reject) => {
      const transaction = this.db!.transaction([storeName], 'readonly')
      const store = transaction.objectStore(storeName)
      const source = indexName ? store.index(indexName) : store
      
      // 首先获取总数
      const countRequest = source.count()
      
      countRequest.onsuccess = () => {
        const total = countRequest.result
        const startIndex = (page - 1) * pageSize
        
        if (startIndex >= total) {
          resolve({ data: [], hasMore: false, total })
          return
        }
        
        const request = source.getAll()
        
        request.onsuccess = () => {
          const allData = request.result
          const startIdx = startIndex
          const endIdx = Math.min(startIndex + pageSize, total)
          const data = allData.slice(startIdx, endIdx)
          const hasMore = endIdx < total
          
          resolve({ data, hasMore, total })
        }
        
        request.onerror = () => {
          reject(new Error(`Failed to paginate ${storeName}`))
        }
      }
      
      countRequest.onerror = () => {
        reject(new Error(`Failed to count ${storeName}`))
      }
    })
  }

  /**
   * 批量操作
   */
  async batch<T extends keyof StoreTables>(
    operations: Array<{
      type: 'add' | 'update' | 'delete'
      storeName: T
      data?: StoreTables[T]
      id?: string
    }>
  ): Promise<void> {
    await this.ensureInitialized()

    const storeNames = [...new Set(operations.map(op => op.storeName))]
    
    return new Promise((resolve, reject) => {
      const transaction = this.db!.transaction(storeNames, 'readwrite')
      
      let completedOperations = 0
      const totalOperations = operations.length
      
      const checkCompletion = () => {
        completedOperations++
        if (completedOperations === totalOperations) {
          resolve()
        }
      }
      
      operations.forEach(operation => {
        const store = transaction.objectStore(operation.storeName)
        let request: IDBRequest
        
        switch (operation.type) {
          case 'add':
            if (operation.data) {
              request = store.add(operation.data)
            } else {
              reject(new Error('Data required for add operation'))
              return
            }
            break
          case 'update':
            if (operation.data) {
              request = store.put(operation.data)
            } else {
              reject(new Error('Data required for update operation'))
              return
            }
            break
          case 'delete':
            if (operation.id) {
              request = store.delete(operation.id)
            } else {
              reject(new Error('ID required for delete operation'))
              return
            }
            break
          default:
            reject(new Error(`Unknown operation type: ${operation.type}`))
            return
        }
        
        request.onsuccess = checkCompletion
        request.onerror = () => {
          reject(new Error(`Batch operation failed: ${operation.type}`))
        }
      })
      
      transaction.onerror = () => {
        reject(new Error('Batch transaction failed'))
      }
    })
  }

  /**
   * 导出数据
   */
  async exportData(): Promise<Record<string, any[]>> {
    await this.ensureInitialized()

    const result: Record<string, any[]> = {}
    const storeNames = ['hospitals', 'floors', 'pois', 'scenarios', 'simulations', 'assets', 'hospital_buildings', 'departments', 'medical_equipment']
    
    for (const storeName of storeNames) {
      result[storeName] = await this.getAll(storeName as keyof StoreTables)
    }
    
    return result
  }

  /**
   * 导入数据 - 使用upsert避免重复键冲突
   */
  async importData(data: Record<string, any[]>): Promise<void> {
    await this.ensureInitialized()

    // 直接逐个插入/更新，避免批处理中的键冲突
    for (const [storeName, items] of Object.entries(data)) {
      if (Array.isArray(items)) {
        for (const item of items) {
          try {
            await this.upsert(storeName as keyof StoreTables, item)
          } catch (error) {
            console.warn(`Failed to import item to ${storeName}:`, error)
            // 继续处理其他数据，不中断整个导入过程
          }
        }
      }
    }
  }

  /**
   * 关闭数据库连接
   */
  close(): void {
    if (this.db) {
      this.db.close()
      this.db = null
    }
  }
}

// 创建全局实例
export const dbService = new IndexedDBService()

// 导出便捷方法
export const hospitalDB = {
  // 数据库初始化Promise
  get initPromise() {
    return dbService.initPromise
  },
  
  // 医院相关
  async addHospital(hospital: Omit<HospitalData, 'id' | 'createdAt' | 'updatedAt'>) {
    const data: HospitalData = {
      ...hospital,
      id: `hospital_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
      createdAt: new Date(),
      updatedAt: new Date()
    }
    await dbService.add('hospitals', data)
    return data
  },

  async getHospitals() {
    return dbService.getAll('hospitals')
  },

  async getHospital(id: string) {
    return dbService.get('hospitals', id)
  },

  async updateHospital(hospital: HospitalData) {
    hospital.updatedAt = new Date()
    return dbService.update('hospitals', hospital)
  },

  async deleteHospital(id: string) {
    return dbService.delete('hospitals', id)
  },

  // POI相关
  async addPOI(poi: Omit<POIData, 'id' | 'createdAt' | 'updatedAt'>) {
    const data: POIData = {
      ...poi,
      id: `poi_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
      createdAt: new Date(),
      updatedAt: new Date()
    }
    await dbService.add('pois', data)
    return data
  },

  async getPOIsByHospital(hospitalId: string) {
    return dbService.getByIndex('pois', 'hospitalId', hospitalId)
  },

  async getPOIsByFloor(floorId: string) {
    return dbService.getByIndex('pois', 'floorId', floorId)
  },

  async updatePOI(poi: POIData) {
    poi.updatedAt = new Date()
    return dbService.update('pois', poi)
  },

  async deletePOI(id: string) {
    return dbService.delete('pois', id)
  },

  // 场景相关
  async addScenario(scenario: Omit<ScenarioData, 'id' | 'createdAt' | 'updatedAt'>) {
    const data: ScenarioData = {
      ...scenario,
      id: `scenario_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
      createdAt: new Date(),
      updatedAt: new Date()
    }
    await dbService.add('scenarios', data)
    return data
  },

  async getScenariosByHospital(hospitalId: string) {
    return dbService.getByIndex('scenarios', 'hospitalId', hospitalId)
  },

  // 医院建筑相关
  async addHospitalBuilding(building: Omit<HospitalBuildingData, 'id' | 'createdAt' | 'updatedAt'>) {
    const data: HospitalBuildingData = {
      ...building,
      id: `building_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
      createdAt: new Date(),
      updatedAt: new Date()
    }
    await dbService.add('hospital_buildings', data)
    return data
  },

  async getHospitalBuildings() {
    return dbService.getAll('hospital_buildings')
  },

  async getHospitalBuildingsByHospital(hospitalId: string) {
    return dbService.getByIndex('hospital_buildings', 'hospitalId', hospitalId)
  },

  async getHospitalBuilding(id: string) {
    return dbService.get('hospital_buildings', id)
  },

  async updateHospitalBuilding(building: HospitalBuildingData) {
    building.updatedAt = new Date()
    return dbService.update('hospital_buildings', building)
  },

  async deleteHospitalBuilding(id: string) {
    return dbService.delete('hospital_buildings', id)
  },

  // 科室相关
  async addDepartment(department: Omit<DepartmentData, 'id' | 'createdAt' | 'updatedAt'>) {
    const data: DepartmentData = {
      ...department,
      id: `dept_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
      createdAt: new Date(),
      updatedAt: new Date()
    }
    await dbService.add('departments', data)
    return data
  },

  async getDepartmentsByHospital(hospitalId: string) {
    return dbService.getByIndex('departments', 'hospitalId', hospitalId)
  },

  async getDepartmentsByBuilding(buildingId: string) {
    return dbService.getByIndex('departments', 'buildingId', buildingId)
  },

  async getDepartmentsByFloor(floorId: string) {
    return dbService.getByIndex('departments', 'floorId', floorId)
  },

  async getDepartment(id: string) {
    return dbService.get('departments', id)
  },

  async updateDepartment(department: DepartmentData) {
    department.updatedAt = new Date()
    return dbService.update('departments', department)
  },

  async deleteDepartment(id: string) {
    return dbService.delete('departments', id)
  },

  // 医疗设备相关
  async addMedicalEquipment(equipment: Omit<MedicalEquipmentData, 'id' | 'createdAt' | 'updatedAt'>) {
    const data: MedicalEquipmentData = {
      ...equipment,
      id: `equip_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
      createdAt: new Date(),
      updatedAt: new Date()
    }
    await dbService.add('medical_equipment', data)
    return data
  },

  async getMedicalEquipmentByHospital(hospitalId: string) {
    return dbService.getByIndex('medical_equipment', 'hospitalId', hospitalId)
  },

  async getMedicalEquipmentByDepartment(departmentId: string) {
    return dbService.getByIndex('medical_equipment', 'departmentId', departmentId)
  },

  async getMedicalEquipmentByFloor(floorId: string) {
    return dbService.getByIndex('medical_equipment', 'floorId', floorId)
  },

  async getMedicalEquipment(id: string) {
    return dbService.get('medical_equipment', id)
  },

  async updateMedicalEquipment(equipment: MedicalEquipmentData) {
    equipment.updatedAt = new Date()
    return dbService.update('medical_equipment', equipment)
  },

  async deleteMedicalEquipment(id: string) {
    return dbService.delete('medical_equipment', id)
  },

  // 通用方法
  async getAll<T extends keyof StoreTables>(storeName: T): Promise<StoreTables[T][]> {
    return dbService.getAll(storeName)
  },

  async add<T extends keyof StoreTables>(storeName: T, data: StoreTables[T]): Promise<void> {
    return dbService.add(storeName, data)
  },

  async update<T extends keyof StoreTables>(storeName: T, data: StoreTables[T]): Promise<void> {
    return dbService.update(storeName, data)
  },

  async upsert<T extends keyof StoreTables>(storeName: T, data: StoreTables[T]): Promise<string> {
    return dbService.upsert(storeName, data)
  }
}